package cn.reinforce.web.fly.config;

import cn.reinforce.web.fly.common.ErrorCodes;
import cn.reinforce.web.fly.model.Result;
import com.alibaba.druid.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * 自定义异常处理
 * @author 幻幻Fate
 * @create 2018/2/23
 * @since
 */
@Controller
public class FateErrorController implements ErrorController {

    private static final String ERROR_PATH = "/error";

    @Autowired
    private ErrorAttributes errorAttributes;

    @Value("spring.profiles.active")
    private String evn;

    @GetMapping(value = ERROR_PATH, produces= MediaType.TEXT_HTML_VALUE)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public ModelAndView handleError(HttpServletRequest request, HttpServletResponse response) {
        ModelAndView mv = new ModelAndView(response.getStatus()>= HttpStatus.INTERNAL_SERVER_ERROR.value()?"base/500":"base/404");
        if(response.getStatus()>= HttpStatus.INTERNAL_SERVER_ERROR.value()){
            Map<String,Object> errorAttributes = getErrorAttributes(request, true);
            mv.addObject("errorMsg", ((String)errorAttributes.get("trace")).replace("\r\n", "<br>"));
        }
        return mv;
    }

    @RequestMapping(value = ERROR_PATH,  produces = {MediaType.APPLICATION_JSON_VALUE})
    @ResponseBody
    public Result json(HttpServletRequest request, HttpServletResponse response) {
        if(!StringUtils.equals("pro", evn)) {
            return buildBody(request,true);
        }else{
            return buildBody(request,false);
        }
    }


    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    private Result buildBody(HttpServletRequest request, Boolean includeStackTrace){
        Map<String,Object> errorAttributes = getErrorAttributes(request, includeStackTrace);
        Integer status=(Integer)errorAttributes.get("status");
        String path=(String)errorAttributes.get("path");
        String messageFound=(String)errorAttributes.get("message");
        String message="";
        String trace ="";
        if(!StringUtils.isEmpty(path)){
            message=String.format("Requested path %s with result %s",path,messageFound);
        }
        if(includeStackTrace) {
            trace = (String) errorAttributes.get("trace");
            if(!StringUtils.isEmpty(trace)) {
                message += String.format(" and trace %s", trace);
            }
        }else {
            message = "未知错误，请联系管理员";
        }

        Result result = null;
        if(status >= 500){
            result = new Result(false, ErrorCodes.UNKNOW_ERROR, message, (String) request.getAttribute("requestId"));
        }else {
            result = new Result(false, message);
        }

        return result;
    }

    private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
        WebRequest webRequest = new ServletWebRequest(request);
        return errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
    }
}
